﻿using System;
using System.Data;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Transactions;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace AppCSharp
{

    unsafe class KRTSOperator : _KitharaSmp
    {
        static string _customerNumber = "070075";
        private static readonly Lazy<KRTSOperator> _instance = new Lazy<KRTSOperator>(() => new KRTSOperator());
        Handle shared_data_handle;
        SharedData* shared_data = null;

        string GetErrorStr(int error)
        {
            byte* buf;
            KS_getErrorString(error, &buf, KSLNG_DEFAULT);
            return new string((sbyte*)buf);
        }
        public static KRTSOperator Instance => _instance.Value;
        private KRTSOperator()
        {
            // 1.打开驱动
            int ksError = KS_openDriver(_customerNumber);
            if (ksError != KS_OK)
            {
                throw new Exception(GetErrorStr(ksError));
            }
            // 2.创建共享内存
            fixed(Handle* shared_handle = &shared_data_handle)
            ksError = KS_createSharedMemEx(
                shared_handle,
                "",
                sizeof(SharedData),
                KSF_NO_FLAGS);
            if (ksError != KS_OK)
            {
                throw new Exception(GetErrorStr(ksError));
            }
            // 3. 获取共享内存
            fixed (SharedData** data = &shared_data)
            {
                ksError = KS_getSharedMemEx(
                            shared_data_handle,
                            (void**)data,
                            KSF_NO_FLAGS);
                if (ksError != KS_OK)
                {
                    throw new Exception(GetErrorStr(ksError));
                }
            }
        }
        ~KRTSOperator()
        {
            // 1. 释放共享内存
            if (shared_data_handle.value() == 0)
            {
                int ksError = KS_freeSharedMemEx(shared_data_handle, KSF_NO_FLAGS);
                // 2. 关闭驱动
                KS_closeDriver();
            }
            Console.WriteLine("KRTS end");
        }

        public void Start()
        {
            if (shared_data == null)
            {
                throw new Exception("KRTSOperator: shared_data is null");
            }
            // 1.加载内核dll
            Handle hInvalidHandle = new Handle(KS_INVALID_HANDLE);
            int ksError = KS_loadLibraryKernel(
                &shared_data->kernel_handle,
                "TestKernel.dll",
                "",
                null,
                KSF_DIRECT_EXEC);
            if (ksError != KS_OK)
            {
                throw new Exception(GetErrorStr(ksError));
            }
            // 2.枚举和打开网卡
            NativeBuffer device = new NativeBuffer(256);
            outputTxt(" ");
            outputTxt("Following devices were found:");
            for (int i = 0; ; ++i)
            {
                ksError = KS_enumDevices(
                            "NET",                                // Type which to look for
                            i,                                    // Enumeration index, starting at zero
                            device.buffer(),                      // Buffer for device name
                            KSF_NO_FLAGS);                        // Flags, here none
                if (ksError != KS_OK)
                {
                    if (KSERROR_CODE(ksError) != KSERROR_DEVICE_NOT_FOUND)
                        outputErr(ksError, "KS_enumDevices", "Unable to query device name!");
                    break;
                }
                outputDec(i, "", ": ", false);
                outputTxt(device.asString());
            }
            outputTxt("Attention!");
            outputTxt("By selecting a device its Windows driver gets removed and replaced by the ");
            outputTxt("appropriate Kithara driver. This will render the network device for the duration");
            outputTxt("of this sample invisible to Windows.");
            outputTxt("Be sure that all other Applications using that device are closed right now!");
            int deviceIndex = inputDec("Device number: ", 0);
            ksError = KS_enumDevices(
                        "NET",                                  // Type which to look for
                        deviceIndex,                            // Index of the chosen device
                        device.buffer(),                        // Buffer for device name
                        KSF_NO_FLAGS);                          // Flags, here none
            if (ksError != KS_OK)
            {
                outputErr(ksError, "KS_enumDevices", "Unable to query selected PCI device name!");
                throw new Exception();
            }
            outputTxt("Selected device: ", false);
            outputTxt(device.asString());
            // ---------- 打开网卡 ---------- 
            KSNetworkAdapterConfig config = new KSNetworkAdapterConfig();
            config.structSize = Marshal.SizeOf<KSNetworkAdapterConfig>();
            ksError = KS_openNetworkAdapter
                (&shared_data->adapter_handle,
                device.asString(),
                ref config,
                KSF_NO_FLAGS);
            if (ksError != KS_OK)
            {
                outputErr(ksError, "打开网卡错误");
                throw new Exception();
            }
            // 3.创建主站
            string pXmlPath = inputTxt(
                                 "Please enter config path to XML files: ",
                                 "E:\\program\\kithara\\Kithara_LinkControl__Demo\\Kithara_Axis_Test_Demo\\xml");
            ksError = KS_createEcatMaster(
                &shared_data->master_handle,
                shared_data->adapter_handle,
                pXmlPath,
                "",
                KSF_NO_FLAGS);
            if (ksError != KS_OK)
            {
                outputErr(ksError, "KS_createEcatMaster");
                throw new Exception();
            }
            Console.WriteLine("EtherCAT Maste Created!");
            // 4.执行内核初始化
            ksError = KS_execKernelFunctionEx(
                shared_data->kernel_handle,
                "InitFuction",
                shared_data_handle,
                hInvalidHandle,
                KSF_NO_FLAGS);
            if (ksError != KS_OK)
            {
                throw new Exception(GetErrorStr(ksError));
            }
        }

        public void Run()
        {
            outputTxt(" ");
            outputTxt("Press [Q] to finish the process data exchange,");
            outputTxt("Press [E] to enable");
            outputTxt("Press [F] to run faster");
            outputTxt("Press [S] to run slower");
            outputTxt("Press [H] to go home");
            outputTxt(" ");
            bool exitSample = false;
            while (!exitSample)
            {
                waitTime(100 * ms);
                outputTxt("\r", false);
                for (int i = 0; i < Global.Total_Axis_Num; i++)
                {
                    outputDec(shared_data->command_position[i], "command_position:", " ", false);
                    outputDec(shared_data->actual_position[i], "actual_position:", " ", false);
                    outputHex04(shared_data->statues[i], "statues:0x", " ", false);
                    outputHex04(shared_data->control_words[i], "control_words:0x", " ", false);
                }
                if (shared_data->error != KS_OK)
                {
                    break;
                }
                ConsoleKeyInfo key = Console.ReadKey(true);
                switch (key.Key)
                {
                    case ConsoleKey.Q:
                        exitSample = true;
                        break;
                    case ConsoleKey.F:

                        break;
                    case ConsoleKey.E:
                        outputTxt("-----------Enable Command------------------");
                        shared_data->command_type = 1;
                        break;
                    case ConsoleKey.D:
                        outputTxt("-----------Disable Command------------------");
                        shared_data->command_type = 2;
                        break;
                    case ConsoleKey.T:
                        outputTxt("-----------Enable Command------------------");
                        break;
                    case ConsoleKey.S:

                        break;
                    case ConsoleKey.H:
                        outputTxt("-----------Home Command------------------");
                        // int device_index = CommonOperator::inputDec("Device number: ", 0);
                        shared_data->command_type = 3;
                        break;
                    case ConsoleKey.C:
                        outputTxt("-----------Home Cancel Command------------------");
                        // int device_index = CommonOperator::inputDec("Device number: ", 0);
                        shared_data->command_type = 4;
                        break;
                    default:
                        continue;
                }

            }
            outputTxt(" ");
        }

        public void Stop()
        {
            // 1. 执行内核退出函数
            Handle hInvalidHandle = new Handle(KS_INVALID_HANDLE);
            int ksError = KS_execKernelFunctionEx(
                    shared_data->kernel_handle,
                    "ExitFuction",
                    shared_data_handle,
                    hInvalidHandle,
                    KSF_NO_FLAGS);
            if (ksError != KS_OK)
            {
                KS_closeDriver();
                throw new Exception(GetErrorStr(ksError));
            }
            // 卸载内核
            ksError = KS_freeKernel(shared_data->kernel_handle);
            if (ksError != KS_OK)
            {
                throw new Exception(GetErrorStr(ksError));
            }
        }
    }

}